package leader

import (
	"context"
	"fmt"
	"github.com/go-logr/logr"
	"gitverse.ru/synapse/kubelatte/pkg/observability/logs"
	"gitverse.ru/synapse/kubelatte/pkg/operator"
	initManager "gitverse.ru/synapse/kubelatte/pkg/operator/init_manager"
	"gitverse.ru/synapse/kubelatte/pkg/storage"
	"gitverse.ru/synapse/kubelatte/pkg/util"
	"net/http"
	"os"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/log"
	"sigs.k8s.io/controller-runtime/pkg/manager"
)

var Mgr manager.Manager

var (
	initMgr           initManager.InitManagerInterface
	templateR         operator.ReconcilerInterface
	triggerR          operator.ReconcilerInterface
	scopeR            operator.ReconcilerInterface
	namespaceR        operator.ReconcilerInterface
	storageController *storage.StorageController
)

func start() {
	operator.IsInit.Mu.Lock()

	if operator.IsInit.IsInit {
		logs.Debug("Already init")
		return
	}

	operator.InitEnv()

	ctx := ctrl.SetupSignalHandler()

	initCtx, cancelInitCtx := context.WithCancel(context.Background())
	defer cancelInitCtx()

	initMgr = initManager.GetInitManager()
	go initMgr.Start(initCtx)

	logs.Debugf("STORAGE started")
	startStorage()

	if operator.IsControllerNeeded("scope") {
		logs.Info("Controller SCOPE started")
		startScopeController()
	}

	if operator.IsControllerNeeded("trigger") {
		logs.Info("Controller TRIGGER started")
		startTriggerController()
	}

	if operator.IsControllerNeeded("template") {
		logs.Info("Controller TEMPLATE started")
		startTemplateController()
	}

	if operator.IsControllerNeeded("triggerInstance") {
		logs.Info("Controller TRIGGER_INSTANCE started")
		go startTriggerInstanceController(ctx)
	}

	logs.Info("Controller NAMESPACE started")
	go startNamespaceController(ctx)

	operator.IsInit.IsInit = true
	operator.IsInit.Mu.Unlock()

	ctrl.SetLogger(logr.Logger{}.WithSink(log.NullLogSink{}))

	//+kubebuilder:scaffold:builder
	if err := Mgr.AddHealthzCheck("healthz", healthz); err != nil {
		logs.Fatal(fmt.Sprintf("Unable to set up health check: %s", err.Error()))
		cancelInitCtx()
		os.Exit(1)
	}
	if err := Mgr.AddReadyzCheck("readyz", readyz); err != nil {
		logs.Fatal(fmt.Sprintf("Unable to set up ready check: %s", err.Error()))
		cancelInitCtx()
		os.Exit(1)
	}

	startLoggerServer(ctx)

	if err := Mgr.Start(ctx); err != nil {
		logs.Fatal(fmt.Sprintf("Problem running manager: %s", err.Error()))
		cancelInitCtx()
		os.Exit(1)
	}
}

func startLoggerServer(ctx context.Context) {
	addr := fmt.Sprintf(":%d", util.IKbltLoggerPort)
	router := http.NewServeMux()
	logs.ChangeDebugLevelServerStart(addr, router)
	go func() {
		if err := http.ListenAndServe(addr, router); err != nil {
			logs.Error(fmt.Sprintf("Error start debug level server: %s", err.Error()))
			os.Exit(1)
		}
		<-ctx.Done()
		logs.Debugf("Stop logger server")
		os.Exit(0)
	}()
}

func startStorage() {
	// [S1] Must start before storage
	storageController = &storage.StorageController{Sync: true}
	storage.Storage = storageController

	storageController.Start(true, false)
}

func SetLeaderAndStart() {
	start()
}
